
	/***********************************************************************************************

		@API
		Module: Data

		Base:
			data	encode				(source, encoding)
			data	decode				(source, decoding)

			json	toJson				(obj	, options*)
			obj		fromJson			(json	, options*)

			xml		toXml					(xnode, options*)
			xnode	fromXml				(xml	, options*)

			csv		toCsv					(ds		, options*)
			ds		fromCsv				(csv	, options*)

		  s+	  serialize			(v, options*)
			v			deserialize		(data)

		Binary:
			crc32	crc32					(data)

			blob	toBase16			(data)
			blob	fromBase16		(b16)

			blob	toBase32			(data)
			blob	fromBase32		(b32)

			blob	toBase64			(data)
			blob	fromBase64		(b64)

		Text:
			blob	toAscii				(s)
			s			fromAscii			(ascii)

			blob	toIso88591		(s)
			s			fromIso88591	(iso88591)

			blob	toUtf8				(s)
			s			fromUtf8			(utf8)

			blob	toUtf16				(s, le*)
			s			fromUtf16			(utf16)

			blob	toUtf16BE			(s)
			s			fromUtf16BE		(utf16be)

			blob	toUtf16LE			(s)
			s			fromUtf16LE		(utf16le)

		Compression:
		  blob	toLz77				(data, options*)
			blob	fromLz77			(lz77, options*)

		  blob	toLzSS				(data, options*)
			blob	fromLzSS			(lzss, options*)

		Options:

			JSON
			json.extended
			json.extension

			json.encoder.prettify
			json.encoder.filter
			json.encoder.transform

			json.decoder.filter
			json.decoder.transform

			XML
			xml.encoder.prettify
			xml.encoder.filter
			xml.encoder.transform

			xml.decoder.validate
			xml.decoder.whitetext
			xml.decoder.text
			xml.decoder.comment
			xml.decoder.cdata
			xml.decoder.pi
			xml.decoder.dtd
			xml.decoder.entity

			CSV
			csv.extended
			csv.separator
			csv.wrapper
			csv.header

			LZ
			lz77.sbl
			lz77.msl
			lz77.mnc

			lzSS.sbl
			lzSS.msl
			lzSS.mnc

		Note: character encoding

		Js stores the string internally in the UCS-2 encoding scheme
		Js can handle strings with code points > 16 bit in some cases
		These code points can be inserted into a js string only as literals in a UTF-8/UTF-16/etc.. source script
		or getting the string from the DOM of an HTML page in UTF-8/UTF-16/etc..
		Not by the \unnnn and not directly append some characters at the string
		Not by String.fromCharCode()
		A js string with these cose points has a length counting the number of 16 bit cells not the number of
		logical character

	***********************************************************************************************/

	//-------------------------------------------------------------------------------
	jsl.Data = (function() {
		try {
			var mod, b16, b32, b64, Obj, m1, m2, fcc, c

			//base encoding
			//-------------------------------------------------------------------------------
			b16 = [ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
						 	65, 66, 67, 68, 69, 70 ]

			b32	= [ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
							50, 51, 52, 53, 54, 55 ]

			b64 = [ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
							97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122,
							48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
							43, 47 ]

			mod 				= new jsl.Module("jsl.Data")
			mod.__b16		= b16
			mod.__b32		= b32
			mod.__b64		= b64
			mod.__b64i	= {}

			Obj = jsl.Object
			Obj.walk(b16, function(v, id) { mod.__b16[v]	= +id })
			Obj.walk(b32, function(v, id) { mod.__b32[v]	= +id })
			Obj.walk(b64, function(v, id) { mod.__b64i[v] = +id })

			//iso-8859-1 code points cache map
			//-------------------------------------------------------------------------------
			m1 	= mod.__m1 = {} //c -> n
			m2	= mod.__m2 = {} //n -> c
			fcc	= String.fromCharCode

			for(var a = 0; a < 256; a++) {
				c = fcc(a)
				m1[c] = a
				m2[a] = c
			}

			//data encoding
			//-------------------------------------------------------------------------------
			mod.__ens		= {
											"json":				"toJson",
											"xml":				"toXml",
											"csv":				"toCsv",
											"serial":			"serialize",

											"ascii":			"toAscii",
											"iso-8859-1":	"toIso88591",
											"utf8": 			"toUtf8",
											"utf16": 			"toUtf16",
											"utf16-be":		"toUtf16BE",
											"utf16-le":		"toUtf16LE",
											"utf16-be*":	"toUtf16",
											"utf16-le*":	function(s) { return jsl.Data.toUtf16(s, true)	},

											"base16":			"toBase16",
											"base32": 		"toBase32",
											"base64": 		"toBase64",

											"lz77":	 			"toLz77",
											"lzss": 			"toLzSS"
										}

			mod.__des		= {
											"json":				"fromJson",
											"xml":				"fromXml",
											"csv":				"fromCsv",
											"serial":			"deserialize",

											"ascii":			"fromAscii",
											"iso-8859-1":	"fromIso88591",
											"utf8": 			"fromUtf8",
											"utf16": 			"fromUtf16",
											"utf16-be":		"fromUtf16BE",
											"utf16-le":		"fromUtf16LE",
											"utf16-be*":	"fromUtf16",
											"utf16-le*":	"fromUtf16",

											"base16":			"fromBase16",
											"base32": 		"fromBase32",
											"base64": 		"fromBase64",

											"lz77": 			"fromLz77",
											"lzss": 			"fromLzSS"
										}

			//serialization
			//-------------------------------------------------------------------------------
			mod.__objs 		= []
			mod.__ids 		= []
			mod.__s				= []
			mod.__cxs			= [ "r" ]
			mod.__c				= false
			mod.__objs.i 	= 0

			//crc32
			//MSB-first (normal)		CRC32 polynomial: 0x04C11DB7
			//LSB-first (reversed) 	CRC32 polynomial: 0xEDB88320
			//-------------------------------------------------------------------------------
			mod.__crc	= null

			//text encoding stream mode
			//-------------------------------------------------------------------------------
			mod.__txt_stream 	= false
			mod.__txt_rb			= 0

			//compression
			//-------------------------------------------------------------------------------
			mod.__LZ_DEFAULT_SBL	= 14	//search buffer lenght
			mod.__LZ_DEFAULT_MSL	= 5		//max sequence length
			mod.__LZ_DEFAULT_MNC 	= 1		//max number of comparisons

			mod.__LS_DEFAULT_SBL	= 14
			mod.__LS_DEFAULT_MSL	= 5
			mod.__LS_DEFAULT_MNC 	= 1

			//internal working options:
			//-------------------------------------------------------------------------------
			mod.__XML_OPTS = {
				filter: 		null,
				transform: 	null,
				prettify: 	false,
				validate: 	false,
				dtd: 				"skip",
				whitetext: 	"collapse",
				text: 			"collapse",
				entity:			"collapse",
				comment:		"preserve",
				cdata:			"preserve",
				pi:					"preserve"
			}

			mod.__JSN_OPTS = {
				extended: 	true,
				prettify: 	false,
				filter: 		null,
				transform: 	null
			}

			mod.__CSV_OPTS = {
				wrapper: 		'"',
				separator: 	",",
				header:			false,
				extended: 	true
			}

			return mod
		}
		catch(e) {
			jsl.throwError(e, "jsl.Data")
		}
	})()
	//Options
	//-------------------------------------------------------------------------------
	jsl.Data.option("json")
	jsl.Data.option("json.encoder")
	jsl.Data.option("json.decoder")
	//-------------------------------------------------------------------------------
	jsl.Data.option("json.extended", {
		dvalue: false,
		setter: function(v, oldv, id) {//!
			jsl.validate(v, "b", id)//!
			return this.__o_json_ex = +v
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("json.extension", {
		dvalue: jsl.Data.__o_json_es = "{~~@#}",
		setter: function(v, oldv, id) {//!
			jsl.validate(v, "s+", id)//!
			return this.__o_json_es = v
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("json.decoder.filter", {
		dvalue: null,
		setter: function(v, oldv, id) {//!
			if(v != null) jsl.validate(v, "f", id)//!
			return this.__o_json_d_fr = v
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("json.decoder.transform", {
		dvalue: null,
		setter: function(v, oldv, id) {//!
			if(v != null) jsl.validate(v, "f", id)//!
			return this.__o_json_d_tr = v
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("json.encoder.prettify", {
		dvalue: false,
		setter: function(v, oldv, id) {//!
			jsl.validate(v, "b", id)//!
			return this.__o_json_e_pr = +v
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("json.encoder.filter", {
		dvalue: null,
		setter: function(v, oldv, id) {//!
			if(v != null) jsl.validate(v, "f", id)//!
			return this.__o_json_e_fr = v
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("json.encoder.transform", {
		dvalue: null,
		setter: function(v, oldv, id) {//!
			if(v != null) jsl.validate(v, "f", id)//!
			return this.__o_json_e_tr = v
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("xml")
	jsl.Data.option("xml.encoder")
	jsl.Data.option("xml.decoder")
	//-------------------------------------------------------------------------------
	jsl.Data.option("xml.encoder.prettify", {
		dvalue:	false,
		setter: function(v, oldv, id) {
			//!
			jsl.validate(v, "b", id)//!
			return this.__o_xml_pr = +v
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("xml.encoder.filter", {
		dvalue: null,
		setter: function(v, oldv, id) {//!
			if(v != null)	jsl.validate(v, "f", id)//!
			return this.__o_xml_fr = v
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("xml.encoder.transform", {
		dvalue: null,
		setter: function(v, oldv, id) {//!
			if(v != null)	jsl.validate(v, "f", id)//!
			return this.__o_xml_tr = v
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("xml.decoder.validate", {
		dvalue:	false,
		setter: function(v, oldv, id) {//!
			jsl.validate(v, "b", id)//!
			return this.__o_xml_vl = +v
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("xml.decoder.whitetext", {
		dvalue:	"collapse",
		setter: function(v, oldv, id) {//!
			jsl.validate(v, "s+[collapse,preserve]", id)//!
			return this.__o_xml_wt = v + ""
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("xml.decoder.text", {
		dvalue:	"collapse",
		setter: function(v, oldv, id) {//!
			jsl.validate(v, "s+[collapse,preserve]", id)//!
			return this.__o_xml_tx = v + ""
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("xml.decoder.comment", {
		dvalue:	"preserve",
		setter: function(v, oldv, id) {
			//!
			jsl.validate(v, "s+[collapse,preserve]", id)//!
			return this.__o_xml_cm = v + ""
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("xml.decoder.cdata", {
		dvalue:	"preserve",
		setter: function(v, oldv, id) {
			//!
			jsl.validate(v, "s+[collapse,preserve]", id)//!
			return this.__o_xml_cd = v + ""
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("xml.decoder.pi", {
		dvalue:	"preserve",
		setter: function(v, oldv, id) {
			//!
			jsl.validate(v, "s+[collapse,preserve]", id)//!
			return this.__o_xml_pi = v + ""
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("xml.decoder.dtd", {
		dvalue:	"skip",
		setter: function(v, oldv, id) {
			//!
			jsl.validate(v, "s+[skip,parse]", id)//!
			return this.__o_xml_dt = +v
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("xml.decoder.entity", {
		dvalue:	"collapse",
		setter: function(v, oldv, id) {
			//!
			jsl.validate(v, "s+[collapse,preserve]", id)//!
			return this.__o_xml_en = v + ""
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("csv")
	//-------------------------------------------------------------------------------
	jsl.Data.option("csv.extended", {
		dvalue:	true,
		setter: function(v, oldv, id) {//!
			jsl.validate(v, "b"	, id)//!
			return !!+v
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("csv.separator", {
		dvalue:	",",
		setter: function(v, oldv, id) {//!
			jsl.validate(v, "sr/^[^\\n]$", id)
			if(v == this.get("csv.wrapper"))	throw jsl.ParamError("e.csv.BadCsvSeparator:csv.separator")//!
			return v + ""
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("csv.wrapper", {
		dvalue:	"\"",
		setter: function(v, oldv, id) {//!
			jsl.validate(v, "sr/^[^\\n]$", id)
			if(v == this.get("csv.separator"))	throw jsl.ParamError("e.csv.BadCsvSeparator:csv.wrapper")//!
			return v + ""
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("csv.header", {
		dvalue:	false,
		setter: function(v, oldv, id) {//!
			jsl.validate(v, "b"	, id)//!
			return !!+v
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("lz77")
	//-------------------------------------------------------------------------------
	jsl.Data.option("lz77.sbl", {
		dvalue:	jsl.Data.__LZ_DEFAULT_SBL,
		setter: function(v, oldv, id) {//!
			jsl.validate(v, "i[2,16]"	, id)//!
			return this.__LZ_DEFAULT_SBL = +v
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("lz77.msl", {
		dvalue:	jsl.Data.__LZ_DEFAULT_SBL,
		setter: function(v, oldv, id) {//!
			jsl.validate(v, "i[2,8]"	, id)//!
			return this.__LZ_DEFAULT_MSL = +v
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("lz77.mnc", {
		dvalue:	jsl.Data.__LZ_DEFAULT_MNC,
		setter: function(v, oldv, id) {//!
			jsl.validate(v, "i[1,255]", id)//!
			return this.__LZ_DEFAULT_MNC = +v
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("lzSS")
	//-------------------------------------------------------------------------------
	jsl.Data.option("lzSS.sbl", {
		dvalue:	jsl.Data.__LS_DEFAULT_SBL,
		setter: function(v, oldv, id) {//!
			jsl.validate(v, "i[2,16]"	, id)//!
			return this.__LS_DEFAULT_SBL = +v
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("lzSS.msl", {
		dvalue:	jsl.Data.__LS_DEFAULT_MSL,
		setter: function(v, oldv, id) {//!
			jsl.validate(v, "i[2,8]"	, id)//!
			return this.__LS_DEFAULT_MSL = +v
		}
	})
	//-------------------------------------------------------------------------------
	jsl.Data.option("lzSS.mnc", {
		dvalue:	jsl.Data.__LS_DEFAULT_MNC,
		setter: function(v, oldv, id) {//!
			jsl.validate(v, "i[1,255]"	, id)//!
			return this.__LS_DEFAULT_MNC = +v
		}
	})
	//-------------------------------------------------------------------------------
  jsl.Data.encode = function(source, encoding) {
		try {
			var en, id, s, a, l//!
			if(arguments.length !== 2)	throw jsl.ParamError()
			jsl.validate(encoding, "s+", "encoding")//!

			en 	= encoding.replace(/\s+/g, "").split(":")//!
			s 	= source
			for(a = 0, l = en.length; a < l; a++) {

				id = en[a].toLowerCase()

				if(!id)							throw jsl.ParamError("BadSyntax:encoding")
				if(!this.__ens[id])	throw jsl.ParamError("e.data.BadEncoding:" + en[a])

				switch(id) {

					case "json":
						if(!jsl.isObject(s))	throw jsl.ParamError("e.data.BadEncodingSequence:encoding:" + id)
						s = "s"
						break;
					case "xml":
						if(!this.XNode.isClassOf(s))	throw jsl.ParamError("e.data.BadEncodingSequence:encoding:" + id)
						s = "s"
						break;
					case "csv":
						if(!jsl.require("datasource").DataSet.isClassOf(s))	throw jsl.ParamError("e.data.BadEncodingSequence:encoding:" + id)
						s = "s"
						break;
					case "serial":
						s = "s"
						break;
					case "ascii":
					case "iso-8859-1":
					case "utf8":
					case "utf16":
					case "utf16-be":
					case "utf16-le":
					case "utf16-be*":
					case "utf16-le*":
						if(!jsl.isString(s))	throw jsl.ParamError("e.data.BadEncodingSequence:encoding:" + id)
						s = new this.Blob
						break;
					case "base16":
					case "base32":
					case "base64":
					case "lz77":
					case "lzss":
						if(!jsl.isString(s) && !jsl.isArrayLike(s) && !(s instanceof this.Blob))
							throw jsl.ParamError("e.data.BadEncodingSequence:encoding:" + id)

						s = new this.Blob
				}
			}//!

			s = source
			for(a = 0, l = en.length; a < l; a++) {
				id 	= this.__ens[en[a].toLowerCase()]
				try 			{ s = typeof id === "string" ? this[id](s) : id(s)					}
				catch(e) 	{	throw jsl.ParamError("e.data.EncodingError:" + en[a], e) 	}
			}

			return s
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
  jsl.Data.decode = function(source, decoding) {
		try {
			var en, id, s, a, l//!
			if(arguments.length !== 2)	throw jsl.ParamError()
			jsl.validate(decoding, "s+", "decoding")//!

			en 	= decoding.replace(/\s+/g, "").split(":")//!
			s 	= source
			for(a = 0, l = en.length; a < l; a++) {

				id = en[a].toLowerCase()

				if(!id)							throw jsl.ParamError("BadSyntax:decoding")
				if(!this.__des[id])	throw jsl.ParamError("e.data.BadDecoding:" + en[a])

				switch(id) {

					case "json":
						if(!jsl.isString(s))	throw jsl.ParamError("e.data.BadDecodingSequence:decoding:" + id)
						s = {}
						break;
					case "xml":
						if(!jsl.isString(s))	throw jsl.ParamError("e.data.BadDecodingSequence:decoding:" + id)
						s = new this.XNode
						break;
					case "csv":
						if(!jsl.isString(s))	throw jsl.ParamError("e.data.BadDecodingSequence:decoding:" + id)
						s = new (jsl.require("datasource")).DataSet(["hi"])
						break;
					case "serial":
						if(!jsl.isString(s))	throw jsl.ParamError("e.data.BadDecodingSequence:decoding:" + id)
						s = "s"
						break;
					case "utf8":
					case "utf16":
					case "utf16-be":
					case "utf16-le":
					case "utf16-be*":
					case "utf16-le*":
						if(!jsl.isString(s) && !jsl.isArrayLike(s) && !(s instanceof this.Blob))
							throw jsl.ParamError("e.data.BadDecodingSequence:encoding:" + id)

						s = "s"
						break;
					case "ascii":
					case "iso-8859-1":
					case "base16":
					case "base32":
					case "base64":
					case "lz77":
					case "lzss":
						if(!jsl.isString(s) && !jsl.isArrayLike(s) && !(s instanceof this.Blob))
							throw jsl.ParamError("e.data.BadDecodingSequence:decoding:" + id)

						s = new this.Blob
				}
			}//!

			s = source
			for(a = 0, l = en.length; a < l; a++) {
				id = this.__des[en[a].toLowerCase()]
				try 			{ s = typeof id === "string" ? this[id](s) : id(s)					}
				catch(e) 	{	throw jsl.ParamError("e.data.DecodingError:" + en[a], e) 	}
			}

			return s
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	/*
		options:
			prettify:		b
	  	extended:		b
	  	filter:			f:filter		(cx) 	-> b
			transform:	f:transform	(cx)	-> s | null
									cx: { id, value, depth, tokens, txt* }

										comma*		id*								value*
			tokens:			[ ","		, "string|{|[|}|]|", "v|{|["]
	*/
	//-------------------------------------------------------------------------------
  jsl.Data.toJson = function(obj, options) {
		try {
			var json, data, cx, i, action, f, t, e, s, r, objs, lvs, lv, i2, txt, txt2, cl, cm, pd, p, r2, r3, r4, r5

			//!
			if(!arguments.length || arguments.length > 2)	throw jsl.ParamError()
			jsl.validate(obj, "o", "obj")
			if(arguments.length === 2)								jsl.validate(options					, "o", "options")
			if(options && options.prettify 	!= null) 	jsl.validate(options.prettify	, "b", "options.prettify")
			if(options && options.filter 		!= null) 	jsl.validate(options.filter		, "f", "options.filter")
			if(options && options.transform	!= null) 	jsl.validate(options.transform, "f", "options.transform")
			if(options && options.extended	!= null) 	jsl.validate(options.extended	, "b", "options.extended")//!

			json 		= []
			data		= []
			lvs			= []
			objs		= []
			cx			= {}
			i				= 0
			i2			= 0
			lv			= 0
			pd			= ""

			r 	= jsl.Data.toJson.__r
			p 	= options && options.prettify 	!= null ? options.prettify 	: this.__o_json_e_pr
			f 	= options && options.filter 		!= null ? options.filter 		: this.__o_json_e_fr
			t 	= options && options.transform 	!= null ? options.transform	: this.__o_json_e_tr
			e 	= options && options.extended 	!= null ? options.extended	: this.__o_json_ex
			s 	= "\"" + this.__o_json_es
			cl	= p ? "\": " : "\":"
			r2 	= /\]|\}/
			r3 	= /(,?)\n?\s*(\{|\[)?([\s\S]*)/
			r4 	= /(,?)\n?\s*("(?:\.|[^\\"])*"|\{|\[):?\s?([\s\S]*)/
			r5  = /[\u0000-\u001F\\"]/g

			action = function(id, v, depth) {
				var y, m, d, h, mn, sc, a, n, ln, txt, txt2, isA, isO, rv, pid

				if(!e && v instanceof Function)	return -1
				isA = this 	instanceof Array
				isO = v 		instanceof Object

				if(depth <= lv)
					while(lvs[i2 - 1] && lvs[i2 - 1].length >= depth) {

						if(p)	txt = "\n" + lvs[--i2] + (data[i2] instanceof Array ? "]" : "}")
						else	txt = data[--i2] instanceof Array ? "]" : "}"

						pd = lvs[i2]
						if(t) {

							cx.id 		= null
							cx.value 	= data[i2]
							cx.depth	= pd.length
							txt2			= txt
							cx.txt		= txt
							cx.tokens	= [ "", txt.match(r2)[0], "" ]

							try				{ txt = t.call(data[i2], cx)															}
							catch(er)	{ throw jsl.ParamError("BadScript:option[transform]", er)	}

							txt = txt == null ? txt2 : txt//!
							if(!jsl.isString(txt))	throw jsl.ParamError("BadReturnType:option[transform]:string")//!
						}
						json[i++] = txt
						cm				= true
					}

				//1 - filter
				//-------------------------------------------------------------------------------
				if(f) {

					cx.id 		= id
					cx.value 	= v
					cx.depth	= depth

					try				{ if(!f.call(this, cx)) return -1												}
					catch(er) { throw jsl.ParamError("BadScript:option[filter]", er)	}
				}

				if(id)
					txt = (cm ? "," : "") 			+
								(p ? "\n" + pd : "") 	+
								(isA ? "" : "\"" 			+
								id.replace(r5, r)     +
								(isO ? "\":" : cl))
				else
					txt = ""

				lv 	= depth
				cm	= true
				rv	= -1//!
				if(isO) {
					ln				= objs.length
					for(a = 0; a < ln; a++) if(v === objs[a])	throw jsl.ParamError("CircularReference:obj")
					objs[ln] = obj
				}//!

				//2 - stringify
				//-------------------------------------------------------------------------------
				//numeric value
				if(typeof v === "number" || v instanceof Number)
					if(isNaN(v))					txt += e ? s + "N\"" 										: "null"
					else if(!isFinite(v))	txt += e ? s + (v > 0 ? "I\"" : "-\"") 	: "null"
					else									txt += v + ""

				//string value
				else if(typeof v === "string" || v instanceof String)
					txt += "\"" + v.replace(r5, r) + "\""

				//boolean value
				else if(typeof v === "boolean" || (v instanceof Boolean))
					txt  += +v ? "true" : "false"

				//Date object
				else if(v instanceof Date)
					if(e)
						txt += s + "d" + v.getTime() + "\""

					else {
						y		= v.getFullYear()

						m		= (v.getMonth() + 1) + ""
						m		= m.length === 2 ? m : "0" + m

						d		= v.getDate() + ""
						d		= d.length === 2 ? d : "0" + d

						h		= v.getHours()
						h		= h.length === 2 ? h : "0" + h

						mn	= v.getMinutes()
						mn	= mn.length === 2 ? mn : "0" + mn

						sc	= v.getSeconds()
						sc	= sc.length === 2 ? sc : "0" + sc

						//(ISO-8601 ZULU time)
						txt += "\"" + y + "-" + m + "-" + d + "T" + h + ":" + mn + ":" + sc + "Z\""
					}

				//Array object
				else if(v instanceof Array) {
					txt			 += "["
					data[i2]	= v
					lvs[i2++]	= pd
					pd 				= pd + "\t"
					cm				= false
					rv				= 0
				}

				else if(e && v instanceof RegExp)
					txt += s + (v + "").replace(r5, r) + "\""

				else if(v instanceof Function)
					//the stringify of a function can start with \n on some platforms and later fromJson
					//see it as string not as function
					txt += s + (v + "").replace(/^[\s\S]*?function/, "function").replace(r5, r) + "\""

				else if(v === undefined)
					if(e)	txt += s + "u\""
					else 	txt += "null"

				else if(v === null)
					txt += "null"

				//generic object (function is skipped)
				else if(isO) {
					txt			 += "{"
					data[i2]	= v
					lvs[i2++]	= pd
					pd 				= pd + "\t"
					cm				= false
					rv				= 0
				}

				//3 - transform
				//-------------------------------------------------------------------------------
				if(t) {

					cx.id 		= id
					cx.value 	= v
					cx.depth	= depth
					txt2			= txt
					cx.txt		= txt
					cx.tokens	= isA ? txt.match(r3).slice(1) : txt.match(r4).slice(1)
					try				{ txt = t.call(this, cx)																	}
					catch(er) { throw jsl.ParamError("BadScript:option[transform]", er)	}

					txt = txt == null ? txt2 : txt//!
					if(!jsl.isString(txt))	throw jsl.ParamError("BadReturnType:option[transform]:string")//!
				}

				json[i++] = txt

				if(!rv) {

					if(v instanceof Array) {
            for(a = 0, n = v.length; a < n; a++)
              action.call(v, a + "", v[a], depth + 1)
					}
					else {

            rv = []
            for(pid in v)
              if(v.hasOwnProperty(pid))
                rv.push(pid)

            rv.sort()
            for(a = 0, n = rv.length; a < n; a++)
              action.call(v, rv[a], v[rv[a]], depth + 1)
					}
				}
			}

			try {
        action("", obj, 0)
			}
			catch(e) 	{
        throw jsl.Error(e).clearStackTrace()
			}

			while(data[--i2]) {

				if(p)	txt = "\n" + lvs[i2] + (data[i2] instanceof Array ? "]" : "}")
				else	txt = data[i2] instanceof Array ? "]" : "}"

				if(t) {

					cx.id 		= null
					cx.value 	= data[i2]
					cx.depth	= lvs[i2].length
					txt2			= txt
					cx.txt		= txt
					cx.tokens	= [ "", txt.match(r2)[0], "" ]

					try				{ txt = t.call(data[i2], cx)															}
					catch(e) 	{ throw jsl.ParamError("BadScript:option[transform]", e)	}

					txt = txt == null ? txt2 : txt//!
					if(!jsl.isString(txt))	throw jsl.ParamError("BadReturnType:option[transform]:string")//!
				}
				json[i++] = txt
			}

			json = json.join("")

			return json
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
  jsl.Data.toJson.__dt = { "\"": "\\\"", "\\": "\\\\", "/": "\\/", "\b": "\\b", "\f": "\\f", "\n": "\\n", "\r": "\\r", "\t": "\\t" }
  //-------------------------------------------------------------------------------
  jsl.Data.toJson.__r  = function(c) {
    return jsl.Data.toJson.__dt[c] || "\\u" + ("0000" + c.charCodeAt(0).toString(16)).slice(-4)
  }
	/*
		options:
			extended:		b
			filter:			f:filter		(cx)	-> b
			transform:	f:transform	(cx)	-> v
									cx: { id*, value, last }
	*/
	//-------------------------------------------------------------------------------
  jsl.Data.fromJson = function(json, options) {
		try {
			var s, i, l, obj, f, t, e, action, cx
			//!
			if(!arguments.length || arguments.length > 2)	throw jsl.ParamError()
			jsl.validate(json, "s+", "json")
			if(arguments.length === 2)								jsl.validate(options					, "o", "options")
			if(options && options.filter		!= null)	jsl.validate(options.filter		, "f", "options.filter")
			if(options && options.transform	!= null)	jsl.validate(options.transform, "f", "options.transform")
			if(options && options.extended	!= null)	jsl.validate(options.extended	, "b", "options.extended")//!

			if(this.__ni_jsn_decode)
				try 			{ obj = this.__ni_jsn_decode(json)					}
				catch(e) 	{	throw jsl.ParamError("BadSyntax:json", e) }

			else {//!
				s = json.replace(/"(\\.|[^"\\])*"/g, "\"\"")

				i = s.search(/[^,":{}\[\]0-9.\-+Eeaflnrstu\n\r\s]/)
	 			if(i !== -1)	throw jsl.ParamError("BadSyntax:json")

				i = s.search(/^[\s\r\n]*(\{|\[)/)
				if(i === -1)	throw jsl.ParamError("json.BadContent:json")

				//an object property name must always be enclosed between quotes
				l = s.match(/([^"\s\r\n]+)[\s\r\n]*:/)
	 			if(l)	throw jsl.ParamError("json.BadProperyName", [ l[1] ])//!

				try 			{ jsl.__ni_jvs_exec("jsl.__tmp.obj=" + json) 	}
				catch(e) 	{ throw jsl.ParamError("BadSyntax:json", e) 	}

				obj = jsl.__tmp.obj
			}

			f = options && options.hasOwnProperty("filter") 		? options.filter 		: this.__o_json_d_fr
			t = options && options.hasOwnProperty("transform") 	? options.transform	: this.__o_json_d_tr
			e = options && options.hasOwnProperty("extended")		? options.extended	: this.__o_json_ex

			if(f || t || e) {

				cx			= {}
				action 	= function(v, id, obj) {
					var rv, s, a, ln, tp, pid

					//1-filter
					if(f) {

						cx.id 		= id
						cx.value 	= v

						//@sys: Explorer - 	catch(e) redefines 'e' to undefined also if no error is rised inside the
						//									try block (only at execution time, when the line is reached in the execution
						//									flow, not at parsing time)
						try				{ if(!f.call(obj, cx)) { delete obj[id]; return				}	}
						catch(er)	{ throw jsl.ParamError("BadScript:option[filter]", er)	}
					}
					//2-transform
					if(t) {

						cx.id 		= id
						cx.value 	= v

						try				{ rv = t.call(obj, cx)																		}
						catch(er)	{ throw jsl.ParamError("BadScript:option[transform]", er)	}

						if(rv !== v)
							//1-object replacement
							if(rv && v && ((tp = typeof rv) === "object" || tp === "function") && ((tp = typeof v) === "object" || tp === "function")) {
								for(pid in v) rv[pid] = v[pid]
								obj[id] = rv
							}
							//2-primitive value
							else
								obj[id] = rv
					}

					//3-extension
					if(e && (v = t ? rv : v) && typeof v === "string") {

						ln	= jsl.Data.__o_json_es.length
						s 	= v.slice(0, ln)

						if(s === jsl.Data.__o_json_es)
							switch(v.charAt(ln)) {

								//1-regexp
								case "/":
									try 			{	a	= v.slice(ln).match(/^\/([\s\S]+)\/([gim]{0,3})$/); obj[id] = RegExp(a[1], a[2])	}
									catch(er) { /**/throw jsl.ParamError("json.BadExtValue", [ "json[RegExp]", obj[id], id ]) /**/	}
									break;

								//2-undefined
								case "u":
									obj[id] = undefined
									//!
									if(v.length !== ln + 1)	throw jsl.ParamError("json.BadExtValue", [ "json", obj[id], id ])//!
									break;

								//3-NaN
								case "N":
									obj[id] = NaN
									//!
									if(v.length !== ln + 1)	throw jsl.ParamError("json.BadExtValue", [ "json", obj[id], id ])//!
									break;

								//4-Infinity
								case "I":
									obj[id] = Infinity
									//!
									if(v.length !== ln + 1)	throw jsl.ParamError("json.BadExtValue", [ "json", obj[id], id ])//!
									break;

								//5--Infinity
								case "-":
									obj[id] = -Infinity
									//!
									if(v.length !== ln + 1)	throw jsl.ParamError("json.BadExtValue", [ "json", obj[id], id ])//!
									break;

								//6-function
								case "f":
									try 			{	jsl.__ni_jvs_exec("jsl.__tmp.f=" + v.slice(ln)) }
									catch(er) { throw jsl.ParamError("json.BadExtValue", [ "json[Function]", obj[id], id ], er)	}
									obj[id] = jsl.__tmp.f
									break;

								//7-date
								case "d":
									rv = new Date(+v.slice(ln + 1))
									//!
									if(isNaN(rv.getTime())) throw jsl.ParamError("json.BadExtValue", [ "json[Date]", rv, id ])//!
									obj[id] = rv
							}
					}

					if(v && typeof v === "object")
						for(pid in v)
							jsl.Object.walk(v[pid], arguments.callee)
				}

				jsl.Object.walk(obj, action)
			}

			return obj
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	/*
		options:
			prettify:	b
			filter:		f:filter(cx) 		-> b
			transorm:	f:transform(cx) -> s | null
								cx: { txt*, end* }
	*/
	//-------------------------------------------------------------------------------
  jsl.Data.toXml = function(xnode, options) {
		try {
			var xml, ns, ds, i, i2, p, f, f2, t, t2, r, cx, pd, s, name, inl, rf, o

			//!
			if(!arguments.length || arguments.length > 2)	throw jsl.ParamError()
			if(xnode == null)															throw jsl.ParamError("NullValue:xnode")
			if(!jsl.Data.XNode.isClassOf(xnode))					throw jsl.ParamError("BadType:xnode:jsl.Data.XNode")

			if(arguments.length === 2)																jsl.validate(options, "o", "options")
			if(arguments.length === 2 && options.filter 		!= null)	jsl.validate(options.filter		, "f", "options.filter")
			if(arguments.length === 2 && options.prettify 	!= null)	jsl.validate(options.prettify	, "b", "options.prettify")
			if(arguments.length === 2 && options.transform	!= null)	jsl.validate(options.transform, "f", "options.transform")//!

			xml	= []
			ns	= []
			ds	= []
			i		= 0
			i2	= 0

			p		= options && options.prettify != null 								? options.prettify 	: this.__o_xml_pr
			f		= f2 = options && options.hasOwnProperty("filter")		? options.filter		: this.__o_xml_fr
			t		= t2 = options && options.hasOwnProperty("transform")	? options.transform	: this.__o_xml_tr
			r		= xnode.__type === 9
			o		= xnode.root().__type === 9 ? 1 : 0
			cx	= {}
			pd	= ""

			//!
			if(f)
				f = function() {
					try 			{ var b = f2.apply(this, arguments)										}
					catch(e) 	{ throw jsl.ParamError("BadScript:option[filter]", e) }
					return b
				}

			if(t)
				t = function() {
					try 			{ var s = t2.apply(this, arguments)												}
					catch(e) 	{ throw jsl.ParamError("BadScript:option[transform]", e)	}

					if(s != null && !jsl.isString(s))	throw jsl.ParamError("BadReturnValue:option[transform]:string")
					return s
				}//!

			rf = function(token, g1, g2, g3) {
				if(g1)			return "&lt;"
				else if(g2)	return "&amp;"
				else				return "&quot;"
			}

			xnode.walk(function(node) {
				var b, depth, type, re, lnode, name, s, atts, nss, id, v, vs, i3, l

				b 		= f && !f.call(node, cx)
				depth = node.depth()

				//end tags
				//-------------------------------------------------------------------
				while(i2 && depth <= ds[i2 - 1].length + o) {

					lnode	= ns[--i2]
					name	= lnode.__name
					pd		= ds[i2]

					if(p && !inl)	s = "\n" + pd + "</" + name + ">"
					else 					s = 						"</" + name + ">", inl = false

					if(t) {
							cx.node 	= lnode
							cx.txt		= s
							cx.end 		= true
							s					= t.call(lnode, cx)
							xml[i++]	= s == null ? cx.txt : s
					}
					else
						xml[i++] = s
				}

				if(b) return -1
				type 	= node.__type
				re		= /\s*(\r\n|\r|\n)+\s*/g

				switch(type) {

					//1-element
					//-------------------------------------------------------------------
					case 1:

						ns[i2] 		= node
						ds[i2++]	= pd

						if(p)	s = "\n" + pd + "<" + node.__name
						else	s = 						"<" + node.__name

						pd 		= pd + "\t"
						atts 	= node.__atts || (node.__drv_attributes()	, node.__atts)
						nss		= node.__nss	|| (node.__drv_nss()				, node.__nss)

						vs 	= []
						i3	= 0
						for(id in atts)	if(atts.hasOwnProperty(id)) vs[i3++] = id
						vs.sort()

						for(i3 = 0, l = vs.length; i3 < l; i3++)
							s += " " + vs[i3] + "=\"" + (atts[vs[i3]] + "").replace(/(<)|(&)|(")/g, rf) + "\""

						vs 	= []
						i3	= 0
						for(id in nss)	if(nss.hasOwnProperty(id)) vs[i3++] = id
						vs.sort()

						for(i3 = 0, l = vs.length; i3 < l; i3++)
							s += (vs[i3] ? " xmlns:" + vs[i3] : " xmlns") + "=\"" + (nss[vs[i3]] + "").replace(/(<)|(&)|(")/g, rf) + "\""

						s  += ">"
						v		= node.__value

						if(v) {
							v = (v + "").replace(/(<)|(&)/g, rf)

							if(p && v.search(/[\n\r]/) !== -1)	s += ("\n" + v + "\n").replace(re, "\n" + pd).slice(0, -(pd.length + 1))
							else if(p)													s += v, inl = !(node.__childs || node.__drv_children()).length
							else																s += v
						}
						else																																//child: we force the immediate node construction
							inl = (node.__childs || node.__drv_children()).length === 1 && node.child(0).__type === 3

						break;

					//3-text
					//-------------------------------------------------------------------
					case 3:
						v = node.__value.replace(/(<)|(&)/g, rf)

						if(p && v.search(/[\n\r]/) !== -1)	s = ("\n" + v + "\n").replace(re, "\n" + pd).slice(0, -(pd.length + 1))
						else																s = v
						break;

					//4-cdata
					//-------------------------------------------------------------------
					case 4:
						v = node.__value.replace(/\]\]>/g, "]]&gt;")

						if(p && v.search(/[\n\r]/) !== -1)	s = "\n" + pd +("<![CDATA[\n" + v + "\n").replace(re, "\n\t" + pd).slice(0, -1) + "]]>"
						else if(p)													s = "\n" + pd + "<![CDATA[" 	+ v + "]]>"
						else																s = 						"<![CDATA[" 	+	v + "]]>"
						break;

					//4-entity reference
					//-------------------------------------------------------------------
					case 5:
						s = "&" + node.__name + ";"
						b	= true
						break;

					//7-process-instruction
					//-------------------------------------------------------------------
					case 7:
						v = node.__value.replace(/\?>/g, "?&gt;")

						if(p && v.search(/[\n\r]/) !== -1)	s = "\n" + pd + "<?\n" 	+ node.__name + ("\n" + v + "\n").replace(re, "\n\t" + pd).slice(0, -1) + "?>"
						else if(p)													s = "\n" + pd + "<?" 		+ node.__name + " " 	+ v + "?>"
						else																s = 						"<?" 		+ node.__name + " " 	+ v + "?>"
						break;

					//8-comment
					//-------------------------------------------------------------------
					case 8:
						v = node.__value.replace(/-->/g, "--&gt;")

						if(p && v.search(/[\n\r]/) !== -1)	s = "\n" + pd +("<!--\n"+ v + "\n").replace(re, "\n\t" + pd).slice(0, -1) + "-->"
						else if(p)													s = "\n" + pd + "<!--" 	+ v + "-->"
						else																s = 						"<!--" 	+ v + "-->"
						break;

					//9-document
					//-------------------------------------------------------------------
					case 9:
						//skip
						break;

					//10-document type (DTD)
					//-------------------------------------------------------------------
					case 10:
						v = node.__value

						//1-no subset
						if(v.replace(/"[^"]*"|'[^']*'/g, "").indexOf("[") === -1)
							if(p)	s =	"\n" + pd +	"<!DOCTYPE " + node.__name + " " + v.replace(/[\n\r\s]+/g, " ") + ">"
							else	s = 						"<!DOCTYPE " + node.__name + " " + v + ">"

						//2-subset
						else
							if(p)	{
								v		= v.replace(/\]\s*$/, "")
								re 	= /<!--[\s\S]*?-->|<\?[\s\S]*?\?>|<!(?:[^"'>]+|"[^"]*"|'[^']*')+>/g
								s 	=	"\n" + pd +	"<!DOCTYPE " + node.__name + " " + v.replace(re, "\n" + pd + "\t$&") + "\n" + pd + "]>"
							}
							else
								s = "<!DOCTYPE " + node.__name + " " + v + ">"

						break;

					//default: node type error
					//-------------------------------------------------------------------
					//!
					default:
						throw jsl.ParamError("xml.BadNodeType", [ node.__name, type ])//!
				}

				if(t) {
						cx.node 	= node
						cx.txt		= s
						cx.end 		= false
						s					= t.call(node, cx)
						xml[i++]	= s == null ? cx.txt : s
				}
				else
					xml[i++] = s

				if(b) return -1
			}, !r)

			while(--i2 >= 0) {

				name = ns[i2].__name

				if(p && !inl)	s = "\n" + ds[i2] + "</" + name + ">"
				else 					s =									"</" + name + ">", inl = false

				if(t) {
						cx.node 	= ns[i2]
						cx.txt		= s
						cx.end 		= true
						s					= t.call(ns[i2], cx)
						xml[i++]	= s == null ? cx.txt : s
				}
				else
					xml[i++] = s
			}

			//normalization step
			//-------------------------------------------------------------------
			if(xml.length) xml[0] = xml[0].replace(/^[^<]+/, "")
			return xml.join("").replace(/<(?!!|\?)([^\s\n\r>]+)([^<]*)>[\n\r\s]*<\/\1>/g, "<$1$2/>")
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	/*
		Options:
			validate:		b(false)
			dtd:				skip(d)			| parse
			whitetext: 	collapse(d) | preserve
			text:				collapse(d)	| preserve
			entity:			collapse(d)	| preserve
			comment:		collapse		| preserve(d)
			cdata:			collapse		| preserve(d)
			pi:					collapse		| preserve(d)
	*/
	//-------------------------------------------------------------------------------
  jsl.Data.fromXml = function(xml, options) {
		try {
			var re, re0, source, doc, i, cm, pi, cd, dtd, es, e, dt, wt, ec, en, xd//!
			if(!arguments.length || arguments.length > 2)	throw jsl.ParamError()
			jsl.validate(xml, "s+", "xml")
			if(arguments.length === 2)								jsl.validate(options, "o", "options")
			if(options && options.validate 	!= null)	jsl.validate(options.validate		, "b"											, "options.validate")
			if(options && options.dtd 			!= null)	jsl.validate(options.dtd				, "s+[skip,parse]"				, "options.dtd")
			if(options && options.whitetext != null)	jsl.validate(options.whitetext	, "s+[collapse,preserve]"	, "options.whitetext")
			if(options && options.entity 		!= null)	jsl.validate(options.entity			, "s+[collapse,preserve]"	, "options.entity")
			if(options && options.text 			!= null)	jsl.validate(options.text				, "s+[collapse,preserve]"	, "options.text")
			if(options && options.comment 	!= null)	jsl.validate(options.comment		, "s+[collapse,preserve]"	, "options.comment")
			if(options && options.cdata 		!= null)	jsl.validate(options.cdata			, "s+[collapse,preserve]"	, "options.cdata")
			if(options && options.pi 				!= null)	jsl.validate(options.pi					, "s+[collapse,preserve]"	, "options.pi")
			//!

			//1-validation
			//-------------------------------------------------------------------------------
			if(options && options.validate != null ? +options.validate : this.__o_xml_vl)
				this.__ni_xml_validate(xml)

			//2-normalization
			//-------------------------------------------------------------------------------
			//@sys: Explorer - native xml parser tries to be helpful and hides text nodes that contain only whitetext and newline

			i = 0
			cm = (options && options.comment 		|| this.__o_xml_cm) == "collapse"
			cd = (options && options.cdata			|| this.__o_xml_cd) == "collapse"
			pi = (options && options.pi 				|| this.__o_xml_pi) == "collapse"
			wt = (options && options.whitetext 	|| this.__o_xml_wt) != "preserve"
			en = (options && options.dtd 				|| this.__o_xml_dt) != "parse"
			ec = (options && options.entity 		|| this.__o_xml_en) != "preserve" && !en

			e	 =  ">" + (wt ? "[\\s\\n\\r]+(?=<)" : "")
			re = 	"(<!--[\\s\\S]*?--" 							+ (cm ? e : "(?=>)") + ")|"		+	//comments
						"(<\\?[\\s\\S]*?\\?" 							+ (pi ? e : "(?=>)") + ")|" 	+ //p-instruction
						"(<!\\[CDATA\\[[\\s\\S]*?\\]\\]" 	+ (cd ? e : "(?=>)") + ")|" 	+ //CDATA sections
						"(<!DOCTYPE[\\s\\r\\n](?:<!--[\\s\\S]*?-->|<\\?[\\s\\S]*?\\?>|[^\"'\\[>]+|\"[^\"]*\"|'[^']*'|\\[[^\\]]*])+(?=>))|"	+	//doctype
						"<(?:[^\"'/>]|\"[^\"]*\"|'[^']*')+/(?=>)|"											+ //closed element
						"<((/?)[^\\s\\r\\n>]+)(?=(?:[^\"'>]|\"[^\"]*\"|'[^']*')*>)|"		+	//tag
						"(>)[\\s\\n\\r]+(?=<)"																						//whitetext

			if(ec)
				re += "|&(?!lt|gt|amp|apos|quot|#x?\\d+)([^;'\"<>]+);"

			source = xml.replace(RegExp(re, "g"),
				function(token, g1, g2, g3, g4, g5, g6, g7, g8) {

					if(g5)						return token + "@" + (g6 ? --i : i++)
					else if(g7 && wt)	return ">"
					else if(g1 && cm)	return ""
					else if(g2 && pi)	return ""
					else if(g3 && cd)	return ""
					else if(g8 && ec)	return jsl.Data.XNode.__drv_en_resolve(g8, es)
					else if(g4 && !en) {

						g4 = g4.replace(/&#(x?\d+);/g, function(s){ return String.fromCharCode("0" + s) })
						re 	= /<!ENTITY[\s\n\r]+([^%\s\n\r][^\s\n\r]*)[\s\n\r]+(?:("[^"]*")|('[^']*'))[\s\n\r]*>/g

						es = {}
						while((e = re.exec(g4))) es[e[1]] = (e[2] || e[3]).slice(1, -1)

						es["@dtd"]					= dtd
						es["@os"]						= options || {}
						es["@os"].validate 	= false
					}

					return token
				})

			//3-document node creation
			//-------------------------------------------------------------------------------
			cm = cm ? "" : "!--[\\s\\S]*?-->|"
			pi = pi ? "" : "\\?[\\s\\S]*?\\?>|"
			cd = cd ? "" : "![CDATA[\\s\\S]*?]]>|"
			en = en || ec ? "" : "&(?!lt|gt|amp|apos|quot|#x?\\d+)[^;'\"<>]+;|"
			dt = "!DOCTYPE[\\s\\r\\n](?:<!--[\\s\\S]*?-->|<\\?[\\s\\S]*?\\?>|[^\"'\\[>]+|\"[^\"]*\"|'[^']*'|\\[[^\\]]*])+>|"

			re0 =
				en																		+ //entity ref.
				"[^<" + (en ? "&" : "") + "]+|<(?:"		+ //text
				dt																		+ //doctype
				cm 																		+ //comment
				pi																		+ //p-instruction
				cd																		+	//cdata
				"(?:[^\"'/>]|\"[^\"]*\"|'[^']*')+/>|"	+	//closed element
				"([^\\s\\n\\r>]+)(?:"									+ //element
					en																	+ //entity ref.
					"[^<" + (en ? "&" : "") + "]+|" 		+
					(cm ? "<" + cm : "")								+
					(pi ? "<" + pi : "")								+
					(cd ? "<" + cd : "")								+
					"<(?!/\\1)[^<]+" 										+
				")*?</\\1[\\s\\n\\r]*>)"

			xd 						= new this.XNode
			xd.__name			= "#document"
			xd.__type			= 9
			xd.__value		= null
			xd.__cix			= 0
			xd.__drv_re		= RegExp(re0, "g")
			xd.__drv_txt	=	"<d>" + source + "</d>"
			xd.__drv_tc		= (options && options.text || this.__o_xml_tx) != "preserve"
			xd.__drv_emap = en ? es : null

			//4-dtd check
			//-------------------------------------------------------------------------------
			try 			{ dtd = xd.select("chd::@dtd[1]")		 					}
			catch(e) 	{ throw jsl.ParamError("SyntaxError:xml", e)	}

			//if a dtd is found doc is not yet created. We replace immediately the re to speed up the
			//creation of the node if whitespace collapsing is true
			if(dtd) xd.__drv_re = RegExp(re0.replace(/!DOCTYPE[\s\S]+?\+>|/, ""), "g")

			try 			{ doc = xd.select("chd::[1]")		 							}
			catch(e) 	{ throw jsl.ParamError("SyntaxError:xml", e)	}

			//!
			if(!doc) throw jsl.ParamError("SyntaxError:xml")//!
			if(!dtd) doc.__drv_re = RegExp(re0.replace(/!DOCTYPE[\s\S]+?\+>\|/, ""), "g")

			//-------------------------------------------------------------------------------
			return doc
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	/*
	 ds:       DataSet
	 options:  separator, wrapper, extended, header
	*/
	//-------------------------------------------------------------------------------
  jsl.Data.toCsv = function(ds, options) {
		try {
			var os, re, re2, rs, n, md, nm, a, tp, b, v, wp, hd

			os = options || {}
			jsl.require("datasource")

			//!
			if(!arguments.length || arguments.length > 2)  throw jsl.ParamError()
			if(!jsl.DataSource.DataSet.isClassOf(ds))	     throw jsl.ParamError("BadType:ds:DataSet")
			if(arguments.length === 2)                     jsl.validate(os, "o", "options")
			if(os.separator != null)		                   jsl.validate(os.separator, 	"sr/^[^\\r\\n]$", "options.separator")
			if(os.wrapper		!= null)		                   jsl.validate(os.wrapper, 		"sr/^[^\\r\\n]$", "options.wrapper")
			if(os.extended 	!= null)		                   jsl.validate(os.extended, 	"b", "options.extended")
			if(os.header		!= null)		                   jsl.validate(os.header,"b", "options.header")//!

			os.separator = os.separator	|| this.get("csv.separator")
			os.wrapper   = os.wrapper		|| this.get("csv.wrapper")
			os.extended  = os.extended 	!= null ? os.extended : this.get("csv.extended")
			os.header    = os.header 		!= null ? os.header 	: this.get("csv.header")

			//!
			if(os.separator == os.wrapper)	throw jsl.ParamError("e.csv.BadCsvSeparator:options.separator")//!

      wp  = os.wrapper
			re 	= RegExp("[\\" + os.separator + "\\" + wp + "\\n\\r]")
			re2	= RegExp("\\" + wp, "g")

			rs 	= ds.toArray(false)
      n   = rs.length
			md 	= ds.metadata()
			nm 	= md.length

			for(a = 0; a < nm; a++) {

				tp = md[a].type

				//1-date
				if(tp === "d")
					for(b = 0; b < n; b++) {
						v = +rs[b][a] + ""
						rs[b][a] = re.test(v)
							? wp + v.replace(re2, wp + wp) + wp
							: v
					}

				//2-xml
				else if(tp === "xml")
					for(b = 0; b < n; b++) {
						v = rs[b][a] != null ? this.toXml(rs[b][a], this.__XML_OPTS) : "null"
						rs[b][a] = re.test(v)
							? wp + v.replace(re2, wp + wp) + wp
							: v
				}

				//3-json
				else if(tp === "json")
					for(b = 0; b < n; b++) {
						v = rs[b][a] != null ? this.toJson(rs[b][a], this.__JSN_OPTS) : "null"
						rs[b][a] = re.test(v)
							? wp + v.replace(re2, wp + wp) + wp
							: v
				}

				//4-obj
				else if(tp === "any")
					for(b = 0; b < n; b++) {
						v = rs[b][a] != null ? this.serialize(rs[b][a]) : "null"
						rs[b][a] = re.test(v)
							? wp + v.replace(re2, wp + wp) + wp
							: v
					}

				//5-blob
				else if(tp === "blob")
					for(b = 0; b < n; b++) {
						v = rs[b][a] != null ? rs[b][a].toString(16) : "null"
						rs[b][a] = re.test(v)
							? wp + v.replace(re2, wp + wp) + wp
							: v
					}

				//6-other
				else
					for(b = 0; b < n; b++) {
						v = rs[b][a] + ""
						rs[b][a] = re.test(v)
							? wp + v.replace(re2, wp + wp) + wp
							: v
					}
			}

			if(os.header) {
				n++
				hd = []
        for(a = 0; a < nm; a++) hd[a] = md[a].id + (os.extended ? "(" + md[a].type + ")" : "")
				rs.unshift(hd)
			}

			for(a = 0; a < n; a++) rs[a] = rs[a].join(os.separator)
			return rs.join("\n")
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
  jsl.Data.fromCsv = function(csv, options) {
		try {
			var os, sp, wp, re, rs, tk, dt, c, b, r, i, hd, nl, s, ds, mx, ex, ts

			os = options || {}

			//!
			if(!arguments.length || arguments.length > 2)	throw jsl.ParamError()
			jsl.validate(csv, "s", "csv")
			if(arguments.length === 2)	jsl.validate(os, "o", "options")
			if(os.separator != null)		jsl.validate(os.separator, 	"sr/^[^\\r\\n]$", "options.separator")
			if(os.wrapper		!= null)		jsl.validate(os.wrapper, 		"sr/^[^\\r\\n]$", "options.wrapper")
			if(os.extended 	!= null)		jsl.validate(os.extended, 	"b", "options.extended")
			if(os.header		!= null)		jsl.validate(os.header,			"b", "options.header")//!

			sp = os.separator || this.get("csv.separator")
			wp = os.wrapper		|| this.get("csv.wrapper")
			ex = os.extended 	!= null ? os.extended : this.get("csv.extended")
			hd = os.header 		!= null ? os.header 	: this.get("csv.header")

			//!
			if(sp == wp)	throw jsl.ParamError("e.csv.BadCsvSeparator:options.separator")//!

			sp = "\\" + sp
			wp = "\\" + wp
			nl = "\\n\\r"
			tk = sp + "|\\n\\r|\\r\\n|\\n|\\r|$"

			re = RegExp(wp + "([^" + wp + "]|" + wp + wp + ")*" + wp + "|"	+	//wrapped v
									"[^" + sp + nl + "]+|" 															+	//v
									"(" + tk + ")", "g")																	//no data

			dt = csv.match(re)
			re 	= RegExp(wp + wp, "g")
			wp = wp.charAt(1)
			sp = sp.charAt(1)

			rs 	= []
			r		= [ "" ]
			b		= 0
			i 	= 0
			s		= 0
			mx	= 0

			for(var a = 0, n = dt.length; a < n; a++) {

				tk 	= dt[a]
				c		= tk.charAt(0)

				if(c === sp) {
					r[++i] = ""
					if(i > mx) mx = i
					s = 0
				}

				//2-wrapped value
				else if(c === wp) {//!
					if(s === 1)	throw jsl.ParamError("e.csv.SyntaxError:csv:" + b)//!
					r[i] = tk.slice(1, -1).replace(re, wp)
					s = 1
				}

				//3-value
				else if(c && c !== "\n" && c !== "\r") {//!
					if(s === 1)	throw jsl.ParamError("e.csv.SyntaxError:csv:" + b)//!
					r[i] = tk
					s = 1
				}

				//4-new line
				else {
					rs[b++] = r
					r = [ "" ]
					i = 0
					s = 0
				}
			}

			if(hd) {
				hd = rs.splice(0, 1)[0]

				if(ex) {

					re = /\((.+)\)$/
					ts = { s: 1, "s+": 1, i: 1, "i+": 1, "i++": 1, n: 1, "n+": 1, "n++": 1, "d": 1, "b": 1, "blob": 1, "xml": 1, "json": 1, "any": 1 }
					n	 = rs.length

					for(a = 0; a < hd.length; a++) {

						dt = hd[a].match(re)

						if(dt) {

							dt		= dt[1]
							hd[a] = { id: hd[a].replace(re, ""), type: ts[dt] ? dt : "s" }
							c			= dt.charAt(0)

							if(dt === "d")					for(b = 0; b < n; b++) rs[b][a] = new Date(+rs[b][a])
							else if(dt === "b") 		for(b = 0; b < n; b++) rs[b][a] = rs[b][a] === "true"
							else if(c === "i") 			for(b = 0; b < n; b++) rs[b][a] = +rs[b][a]
							else if(c === "n")  		for(b = 0; b < n; b++) rs[b][a] = +rs[b][a]
							else if(c === "x") 			for(b = 0; b < n; b++) rs[b][a] = rs[b][a] != null ? this.fromXml(rs[b][a],	this.__XML_OPTS) 	: null
							else if(c === "j") 			for(b = 0; b < n; b++) rs[b][a] = rs[b][a] != null ? this.fromJson(rs[b][a],this.__JSN_OPTS) 	: null
							else if(dt === "blob")	for(b = 0; b < n; b++) rs[b][a] = rs[b][a] != null ? new this.Blob(this.Blob.HEX + rs[b][a]) 	: null
							else if(dt === "any") 	for(b = 0; b < n; b++) rs[b][a] = rs[b][a] != null ? this.deserialize(rs[b][a])								: null

						}
					}
				}

				for(a = hd.length; a <= mx; a++)
					hd[a] = "column" + a
			}
			else {
				hd = []
				for(a = 0; a <= mx; a++) hd[a] = "column" + a
			}

			if(mx) {
				ds = new (jsl.require("datasource")).DataSet(hd)
				ds.inject(rs)
			}

			return ds || null
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}

	/*
		Options:
			compress: b
	*/
	//-------------------------------------------------------------------------------
  jsl.Data.serialize = function(v, options) {
		try {
			var hop, t, objs, ids, s, cxs, cx, oi, i, sid, txt, a, l, i2, id, out, b, f//!
			if(arguments.length < 1 || arguments.length > 2)	throw jsl.ParamError()
			if(arguments.length === 2)												jsl.validate(options					, "o", "options")
			if(options && options.compress != null)						jsl.validate(options.compress	, "b", "options.compress")//!

			hop		= Object.prototype.hasOwnProperty
			t 		= typeof v

			objs 	= this.__objs
			ids		= this.__ids
			cxs		= this.__cxs
			cx		= cxs[cxs.length - 1]
			s 		= this.__s

			oi		= objs.length
			i			= s.length

			//start of serialization
			if(!objs.i && options) this.__c = options.compress && options.compress.valueOf()
			objs.i++

			//some objects can be objects but not instance of Object
			//the same applies to the functions
			if((v && t === "object") || t === "function") {

				//1-Array
		 		if(v instanceof Array)
					s[i] = "[];"

				//2-Date
				else if(v instanceof Date)
					s[i] = "new Date(" + +v + ");"

				//3-RegExp
				else if(v instanceof RegExp)
					s[i] = v + ";"

				//4-String
				else if(v instanceof String)
					s[i] = "new String(\"" + v.replace(/\\|"/g	,	"\\$&")
																		.replace(/\r/g		, "\\r")
																		.replace(/\n/g		, "\\n") + "\");"
				//5-Number
				else if(v instanceof Number)
					s[i] = "new Number(" + v + ");"

				//6-Boolean
				else if(v instanceof Boolean)
					s[i] = "new Boolean(" + v + ");"

				//7-Error
				else if(v instanceof Error)
					s[i]	= "new " + jsl.__mlng_object_name(v) + "(\"" + jsl.Error.message(v)	.replace(/\\|"/g,	"\\$&")
																																										.replace(/\r/g	, "\\r")
																																										.replace(/\n/g	, "\\n") + "\");"
				//8-Function object
				else if(t === "function") {

					txt = jsl.__mlng_function_body(v)
					if(txt.replace(/"([^\\"]|\\.)*"|'([^\\']|\\.)*'|\/([^\\\/]|\\.)*\//g, "").search(/\[native code[^\]]*\]/i) !== -1) {

						txt = jsl.__mlng_function_name(v)
						if(typeof jsl.__go[txt] !== "function")	throw jsl.ParamError("serial.BadNConstructor:v(" + jsl.__mlng_function_name(v) + ")")
						else																		s[i] = txt + ";"
					}
					else
						s[i] = v + ";"
				}

				//9-Serializable object
				else if(v.sid && v.sid instanceof Function && v.sid() != null) {

					try 			{ sid	= v.sid() }
					catch(e) 	{	/**/ throw jsl.ScriptError("serial.BadSidMethod", e) /**/ }

					//the sid constructor must exists only at the unserialize process	time
					//a sid can be also expressed in the following form: a["x"\ny"]
					sid = sid	.replace(/\\|"/g,	"\\$&")
										.replace(/\r/g	, "\\r")
										.replace(/\n/g	, "\\n")

					if(jsl.__dbg) {
						txt	 = "(function(){try{var o;"
						txt	+= "f.prototype=" + sid + ".prototype;"
						txt += "if(typeof " 	+ sid + "!==\"function\")throw jsl.TypeError(\"BadType\",[\"" + sid + "\",\"function\"]);"
						txt += "o=new f;o.constructor=" + sid + ";if(jsl.isClass(" + sid + "))o.__class=" + sid + ";return o}"
						txt += "catch(e){throw jsl.Error(\"serial.BadSidConstructor\",[\"" + sid + "\"],e)}"
						txt += "})();"
					}
					else
						txt	= "(f.prototype=" + sid + ".prototype,new f);"

					s[i] = txt
				}

				//10-Simple object
				else
					s[i] = "{};"

				i2				= oi
				b					= t !== "function"
				t					= null
				objs[oi] 	= v
				ids[oi++]	= i++

				for(id in v)
					//@sys: Opera 10.50 - Function.prototype is enumerated
					if(hop.call(v, id) && id !== "constructor" && id !== "__class" && id !== "__proto" && (b || id !== "prototype")) {

						t				= typeof v[id]
						s[i++] 	= cx + "[\"" + id.replace(/\\|"/g,"\\$&").replace(/\r/g, "\\r").replace(/\n/g, "\\n") + "\"]="

						if(v[id] && (t === "object" || t === "function")) {

							for(a = 0, l = objs.length; a < l; a++)
								if(v[id] === objs[a])
									break;

							if(a < l) {
								s[i++] = a ? "_._" + a + ";" : "r;"
								ids[a] > 0 && (ids[a] *= -1)
							}
							else {
								cxs[cxs.length] = "_._" + oi
								this.serialize(v[id])
								i 	= s.length
								oi	= objs.length
							}
						}
						else
							if(t !== "string")	s[i++] = v[id] + ";"
							else 								s[i++] = "\"" + v[id]	.replace(/\\|"/g, "\\$&")
																												.replace(/\r/g	, "\\r")
																												.replace(/\n/g	, "\\n") + "\";"
					}

				if(t && ids[i2] > 0) ids[i2] *= -1
			}
			else if(t !== "string")	s[i++] = v 		+ ";"
			else 										s[i++] = "\"" + v	.replace(/\\|"/g, "\\$&")
																								.replace(/\r/g	, "\\r")
																								.replace(/\n/g	, "\\n") + "\";"
			objs.i--
			cxs.pop()

			//end of serialization
			if(!objs.i) {

				for(a = 1, l = objs.length; a < l; a++)	{
					i = ids[a]
					if(i < 0) s[-i] = "_._" + a + "=" + s[-i]
				}

				//2028 -> LINE 			SEPARATOR -> eval("var a = '\u2028'") -> error
				//2029 -> PARAGRAPH SEPARATOR -> eval("var a = '\u2029'") -> error
				out = s.join("").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029")

				cxs[0]			= "r"
				objs.length = 0
				ids.length	= 0
				s.length		= 0

				if(this.__c) {
					s 				= out.replace(/\u0100-\uffff/g, function(c) { return "\\u" + ("000" + c.charCodeAt(0).toString(16)).slice(-4) })
					f					= String.fromCharCode
					out 			= []
					b					= 0
					this.__c	= false

					for(a = 0, l = s.length; a < l; a++)
						out[b++] = f(s.charCodeAt(a++) << 8 | s.charCodeAt(a))

					//even/odd compression
					if(s.length % 2) 	out = "JSL~SO" + out.join("")
					else 							out = "JSL~SE" + out.join("")
				}
				else
					out	= "JSL~SR" + out
			}

			return out
		}
		catch(e) {
			this.__cxs 		= ["r"]
			this.__objs.i = this.__objs.length = this.__ids.length = this.__s.length = 0
			this.__c			= false
			jsl.throwError(jsl.Error(e).clearStackTrace(), this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
  jsl.Data.deserialize = function(s) {
		try {
			var id, d, out, n, f//!
			if(arguments.length !== 1) throw jsl.ParamError()
			jsl.validate(s, "s+", "s")
			if(s.length <= 6)	throw jsl.ParamError("serial.BadFormat:s")//!

			id = s.slice(0, 6)//!
			if(!(/JSL~S(R|E|O)/).test(id)) throw jsl.ParamError("serial.BadFormat:s")//!

			id 	= id.slice(-1)
			d		= s.slice(6)

			if(id !== "R") {

				out = []
				f		= String.fromCharCode

				for(var a = 0, l = d.length; a < l; a++) {
					n 			= d.charCodeAt(a)
					out[a] 	= f(n >> 8, n & 0xff)
				}

				if(id === "O") out[--a] = out[a].charAt(0)
				d = out.join("")
			}

			try 			{	jsl.__ni_jvs_exec("jsl.__tmp.r=(function(){var f=function(){},_={},r=" + d + "return r})()") }
			catch(e) 	{ throw jsl.ParamError("BadData", e)	}

			return jsl.__tmp.r
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.Data.crc32 = function(data) {
 		try {
			var a, map, i, crc, l, bs//!
			if(arguments.length !== 1)	throw jsl.ParamError()
			jsl.validate(data, "t[al,s,Blob]", "data")//!

			try 			{ bs = this.Blob.toArray(data) }
			catch(e) 	{ if(e instanceof jsl.ParamError) throw e.clearStackTrace()
									else														throw e }

			if(!this.__crc) {

		    for(a = 0, map = {}; a < 256; a++) {

	        for(i = 0, crc = a; i < 8; i++)
            if(crc & 1)	crc = crc >>> 1 ^ 0xEDB88320
            else     		crc >>>= 1

	        map[a] = crc;
		    }

				this.__crc = map
			}

			l		= bs.length
			map = this.__crc
			i		= 0
			crc = -1

	    while(i < l) 	crc = map[(crc ^ bs[i++]) & 0xFF] ^ crc >>> 8
    	return (crc ^ -1) >>> 0
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
  }
	//-------------------------------------------------------------------------------
	jsl.Data.toBase16 = function(data) {
 		try {
			var bs, map, l, b16, a, b

			//!
			if(arguments.length !== 1) throw jsl.ParamError()
			jsl.validate(data, "t[al,s,Blob]", "data")//!

			try 			{ bs = this.Blob.toArray(data) }
			catch(e) 	{ if(e instanceof jsl.ParamError) throw e.clearStackTrace()
									else														throw e }

			map 	= this.__b16
			l 		= bs.length
			b16 	= []
			a			= 0
			b			= 0

			while(a < l) {
		  	b16[b++] 	= map[bs[a] >> 4]
		  	b16[b++] 	= map[bs[a++] & 0x0F]
	  	}

			return new this.Blob(b16)
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
  }
	//-------------------------------------------------------------------------------
  jsl.Data.fromBase16 = function(b16) {
		try {
			var bs, map, l, data, a, b

			//!
			if(arguments.length !== 1) throw jsl.ParamError()
			jsl.validate(b16, "t[al,s,Blob]", "b16")//!

			try 			{ bs = this.Blob.toArray(b16) }
			catch(e) 	{ if(e instanceof jsl.ParamError) throw e.clearStackTrace()
									else														throw e }

			//!
			if(b16.length % 2)																								throw jsl.ParamError("BadValue:b16")
			if(b16.length && !(/^[A-F0-9]+$/).test(this.Blob.toString(b16)))	throw jsl.ParamError("BadValue:b16")//!

			map 	= this.__b16
			l			= bs.length
			data	= []
			a			= 0
			b 		= 0

			while(a < l) data[b++] = map[bs[a++]] << 4 | map[bs[a++]]
   		return new this.Blob(data)
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
  }
	//-------------------------------------------------------------------------------
	jsl.Data.toBase32 = function(data) {
 		try {
			var bs, map, l, b32, a, b, r

			//!
			if(arguments.length !== 1)	throw jsl.ParamError()
			jsl.validate(data, "t[al,s,Blob]", "data")//!

			try 			{ bs = this.Blob.toArray(data) }
			catch(e) 	{ if(e instanceof jsl.ParamError) throw e.clearStackTrace()
									else														throw e }

			map = this.__b32
			l 	= bs.length
			b32 = []
			a		= 0
			b		= 0

			while(a < l) {
		  	b32[b++] 	= map[bs[a] >> 3]
		  	b32[b++] 	= map[(bs[a++] 	& 0x07) << 2 | bs[a] >> 6]
		  	b32[b++] 	= map[(bs[a] 		& 0x3E) >> 1]
		  	b32[b++] 	= map[(bs[a++] 	& 0x01) << 4 | bs[a] >> 4]
		  	b32[b++] 	= map[(bs[a++] 	& 0x0F) << 1 | bs[a] >> 7]
		  	b32[b++] 	= map[(bs[a] 		& 0x7C) >> 2]
		  	b32[b++] 	= map[(bs[a++] 	& 0x03) << 3 | bs[a] >> 5]
		  	b32[b++] 	= map[ bs[a++] 	& 0x1F ]
	  	}

			r = l % 5

			if(r === 1) 			b32[b - 6] = b32[b - 5] = b32[b - 4] = b32[b - 3] = b32[b - 2] = b32[b - 1] = 61
			else if(r === 2) 	b32[b - 4] = b32[b - 3] = b32[b - 2] = b32[b - 1] = 61
			else if(r === 3) 	b32[b - 3] = b32[b - 2] = b32[b - 1] = 61
			else if(r === 4)	b32[b - 1] = 61

			return new this.Blob(b32)
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
  }
	//-------------------------------------------------------------------------------
  jsl.Data.fromBase32 = function(b32) {
		try {
			var bs, map, l, data, a, b

			//!
			if(arguments.length !== 1) throw jsl.ParamError()
			jsl.validate(b32, "t[al,s,Blob]", "b32")//!

			try 			{ bs = this.Blob.toArray(b32) }
			catch(e) 	{ if(e instanceof jsl.ParamError) throw e.clearStackTrace()
									else														throw e }

			//!
			if(b32.length % 8)																																		throw jsl.ParamError("BadValue:b32")
			if(b32.length && !(/^[A-Z2-7]+(={0,1}|={3,4}|={6})$/).test(this.Blob.toString(b32)))	throw jsl.ParamError("BadValue:b32")//!

			map 	= this.__b32
			l			= bs.length
			data	= []
			a			= 0
			b 		= 0

			while(a < l) {
		    data[b++]	= (map[bs[a++]] << 3 | map[bs[a]] >> 2)															;if(bs[a + 1] === 61) break;
				data[b++]	= (map[bs[a++]] << 6 | map[bs[a++]] << 1 | map[bs[a]] >> 4) & 0xFF	;if(bs[a + 1] === 61) break;
		    data[b++]	= (map[bs[a++]] << 4 | map[bs[a]] 	>> 1) 									& 0xFF	;if(bs[a + 1] === 61) break;
		    data[b++]	= (map[bs[a++]] << 7 | map[bs[a++]] << 2 | map[bs[a]] >> 3) & 0xFF 	;if(bs[a + 1] === 61) break;
		    data[b++]	= (map[bs[a++]] << 5 | map[bs[a++]])												& 0xFF
	  	}

   		return new this.Blob(data)
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
  }
	//-------------------------------------------------------------------------------
	jsl.Data.toBase64 = function(data) {
 		try {
			var bs, map, l, b64, a, b, r

			//!
			if(arguments.length !== 1)	throw jsl.ParamError()
			jsl.validate(data, "t[al,s,Blob]", "data")//!

			try 			{ bs = this.Blob.toArray(data) }
			catch(e) 	{ if(e instanceof jsl.ParamError) throw e.clearStackTrace()
									else														throw e }

			map = this.__b64
			l 	= bs.length
			b64 = []
			a		= 0
			b		= 0

			while(a < l) {
		  	b64[b++] 	= map[bs[a] >> 2]
		  	b64[b++] 	= map[(bs[a++] & 0x03) << 4 | bs[a] >> 4]
		  	b64[b++] 	= map[(bs[a++] & 0x0F) << 2 | bs[a] >> 6]
		  	b64[b++] 	= map[ bs[a++] & 0x3F ]
	  	}

			r = l % 3

			if(r === 1) 			b64[b - 2] = b64[b - 1] = 61
			else if(r === 2) 	b64[b - 1] = 61

			return new this.Blob(b64)
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
  }
	//-------------------------------------------------------------------------------
  jsl.Data.fromBase64 = function(b64) {
		try {
			var bs, map, l, data, a, b

			//!
			if(arguments.length !== 1)	throw jsl.ParamError()
			jsl.validate(b64, "t[al,s,Blob]", "b64")//!

			try 			{ bs = this.Blob.toArray(b64) }
			catch(e) 	{ if(e instanceof jsl.ParamError) throw e.clearStackTrace()
									else														throw e }

			//!
			if(b64.length % 4)																															throw jsl.ParamError("BadValue:b64")
			if(b64.length && !(/^[A-Za-z0-9\+\/]+\={0,2}$/).test(this.Blob.toString(b64)))	throw jsl.ParamError("BadValue:b64")//!

			map 	= this.__b64i
			l			= bs.length
			data	= []
			a			= 0
			b 		= 0

			while(a < l) {
		    data[b++]	=  map[bs[a++]] << 2 | map[bs[a]] >> 4					;if(bs[a + 1] === 61) break;
		    data[b++]	= (map[bs[a++]] << 4 | map[bs[a]] >> 2) & 0xFF 	;if(bs[a + 1] === 61) break;
		    data[b++]	= (map[bs[a++]] << 6 | map[bs[a++]])		& 0xFF
	  	}

   		return new this.Blob(data)
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
  }
	//-------------------------------------------------------------------------------
	jsl.Data.toAscii = function(s) {
 		try {
			var blob, bs, map//!
			if(arguments.length !== 1)	throw jsl.ParamError()
			jsl.validate(s, "s", "s")//!

			bs 	= s.split("")
			map	= this.__m1

			for(var a = 0, l = s.length; a < l; a++) {
				bs[a] = map[bs[a]]//!
				if(bs[a] == null || bs[a] > 127)	throw jsl.ParamError("e.data.BadAsciiString:s:" + a + ":" + bs[a])//!
			}

			blob 			= new this.Blob
			blob.__bs	= bs

			return blob
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
  }
	//-------------------------------------------------------------------------------
	jsl.Data.fromAscii = function(ascii) {
 		try {
			var bs, blob//!
			if(arguments.length !== 1)	throw jsl.ParamError()
			jsl.validate(ascii, "t[al,s,Blob]", "ascii")//!

			try 			{ bs = this.Blob.toArray(ascii) }
			catch(e) 	{ throw (e instanceof jsl.ParamError ? e.clearStackTrace() : e) }

			//!
			for(var a = 0, l = bs.length; a < l; a++)
			if(bs[a] & 128)	throw jsl.ParamError("e.data.BadAsciiCode:ascii:" + a + ":" + bs[a])//!

			this.__txt_rb = 0
			blob 					= new this.Blob
			blob.__bs 		= bs

			return blob + ""
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
  }
	//-------------------------------------------------------------------------------
	jsl.Data.toIso88591 = function(s) {
 		try {
			var blob, bs, map//!
			if(arguments.length !== 1)	throw jsl.ParamError()
			jsl.validate(s, "s", "s")//!

			bs 	= s.split("")
			map	= this.__m1

			for(var a = 0, l = s.length; a < l; a++) {
				bs[a] = map[bs[a]]//!
				if(bs[a] == null)	throw jsl.ParamError("e.data.BadIso88591String:s:" + a + ":" + bs[a])//!
				}

			blob 			= new this.Blob
			blob.__bs	= bs

			return blob
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
  }
	//-------------------------------------------------------------------------------
	jsl.Data.fromIso88591 = function(iso88591) {
 		try {
			var bs, blob//!
			if(arguments.length !== 1)	throw jsl.ParamError()
			jsl.validate(iso88591, "t[al,s,Blob]", "iso88591")//!

			try 			{ bs = this.Blob.toArray(iso88591) }
			catch(e) 	{ throw (e instanceof jsl.ParamError ? e.clearStackTrace() : e) }

			this.__txt_rb = 0
			blob 					= new this.Blob
			blob.__bs 		= bs

			return blob + ""
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
  }
	//-------------------------------------------------------------------------------
	jsl.Data.toUtf8 = function(s) {
 		try {
			var utf8, l, a, b, c//!
			if(arguments.length !== 1)	throw jsl.ParamError()
			jsl.validate(s, "s", "s")//!

			l			= s.length
			a			= b = 0
			utf8	= []

			//Only the Unicode first plane (code points U+0000 to U+FFFF) Basic Multilingual Plane or BMP
			//is supported in UCS-2 (~97% characters are the same of UTF-16)
			//charCodeAt return always a unicode point in the range [0-0xFFFF]
			while(a < l) {

				c = s.charCodeAt(a++)

				//!no Unicode points mapped inside the range [0xD800, 0xDFFF]
				if(c >= 0xD800 && c <= 0xDFFF)	throw jsl.ParamError("utf.BadChar:s:" + (a - 1))//!

				//1-ASCII, 1 byte
				if(c < 0x80)
					utf8[b++] = c

				//2-2 bytes
				else if(c < 0x800) {
					utf8[b++] = 192 | c >> 6
					utf8[b++] = 128 | c & 63
				}
				//3-3 bytes
				else if(c < 0xFFFF) {
					utf8[b++] = 224 | c >> 12
					utf8[b++] = 128 | c >> 6 & 63
					utf8[b++] = 128 | c & 63
				}
			}

			return new this.Blob(utf8)
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
  }
	//-------------------------------------------------------------------------------
  jsl.Data.fromUtf8 = function(utf8) {
		try {
			var bs, fcc, a, b, l, s, c, c2, c3, str//!
			if(arguments.length !== 1)	throw jsl.ParamError()
			jsl.validate(utf8, "t[al,s,Blob]", "utf8")//!

			try 			{ bs = this.Blob.toArray(utf8) }
			catch(e) 	{ if(e instanceof jsl.ParamError) throw e.clearStackTrace()
									else														throw e }

			str		= this.__txt_stream
			fcc		= String.fromCharCode
			a 		= b = 0
			l			=	bs.length
			s			= []

			this.__txt_rb = 0

			while(a < l) {

				c = bs[a++]

				//1-1byte
				if(c < 0x80)
					s[b++] = fcc(c)

				//2-2byte
				else if((c & 0xE0) === 0xC0) {
					c2 = bs[a++]

					if(str && c2 == null) {
						this.__txt_rb = 1
						break
					}

					//!
					if((c2 & 0xC0) !== 0x80)	throw jsl.ParamError("utf.BadByte:utf8:" + (a - 1))//!
					s[b++] = fcc(((c & 0x1F) << 6) | (c2 & 0x3F))
				}

				//3-3byte -> 2byte UCS2
				else if((c & 0xF0) === 0xE0) {
					c2 = bs[a++]
					c3 = bs[a++]

					if(str && (c2 == null || c3 == null))  {
						this.__txt_rb = c2 == null ? 2 : 1
						break
					}

					//!
					if((c2 & 0xC0) !== 0x80)	throw jsl.ParamError("utf.BadByte:utf8:" + (a - 2))
					if((c3 & 0xC0) !== 0x80)	throw jsl.ParamError("utf.BadByte:utf8:" + (a - 1))//!

					s[b++] = fcc(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63))
				}

				//!
				//4-4byte not permitted (Js UCS-2 use only 16bit)
				else if((c & 0xF8) === 0xF0)	throw jsl.ParamError("utf.UnicodeCharNotSupported:utf8:" + (a - 1))

				//5-error
				else throw jsl.ParamError("utf.BadByte:utf8:" + (a - 1))//!
			}
			return s.join("")
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
  }
	//-------------------------------------------------------------------------------
	jsl.Data.toUtf16 = function(s, le) {
 		try {//!
			if(!arguments.length || arguments.length > 2)	throw jsl.ParamError()
			jsl.validate(s, "s", "s")
			if(arguments.length === 2)	jsl.validate(le, "b", "le")//!

			return le ? this.toUtf16LE(String.fromCharCode(0xFEFF) + s) :
									this.toUtf16BE(String.fromCharCode(0xFEFF) + s)
		}
		catch(e) {
			throw jsl.Error(e).clearStackTrace().trace(this, arguments)
		}
  }
	//-------------------------------------------------------------------------------
  jsl.Data.fromUtf16 = function(utf16) {
		try {
			var bs, bom, s//!
			if(arguments.length !== 1)	throw jsl.ParamError()
			jsl.validate(utf16, "t[al,s,Blob]", "utf16")//!

			bs = this.Blob.toArray(utf16)

			if(bs.length) {//!
				if(!this.__txt_stream && bs.length % 2) throw jsl.ParamError("BadSize:utf16")//!

				bom = bs[0] << 8 | bs[1]
				bs.shift()
				bs.shift()

				if(bom === 0xFEFF)			s = this.fromUtf16BE(bs)
				else if(bom === 0xFFFE)	s = this.fromUtf16LE(bs)//!
				else										throw jsl.ParamError("utf.BadUtf16Bom:utf16")//!
			}

			return s || ""
		}
		catch(e) {
			throw jsl.Error(e).clearStackTrace().trace(this, arguments)
		}
  }
	//-------------------------------------------------------------------------------
	jsl.Data.toUtf16BE = function(s) {
 		try {
			var utf16, l, a, b, c//!
			if(arguments.length !== 1)	throw jsl.ParamError()
			jsl.validate(s, "s", "s")//!

			utf16	= []
			l			= s.length
			a			= b = 0

			while(a < l) {
				c	= s.charCodeAt(a++)

				//! no Unicode points mapped inside the range [0xD800, 0xDFFF]
				if(c >= 0xD800 && c <= 0xDFFF)	throw jsl.ParamError("utf.BadChar:s:" + (a - 1))//!

				utf16[b++] 	= c >> 8
				utf16[b++] 	= c & 0xFF
			}

			return new this.Blob(utf16)
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
  }
	//-------------------------------------------------------------------------------
  jsl.Data.fromUtf16BE = function(utf16be) {
		try {
			var bs, l, a, b, s, fcc//!
			if(arguments.length !== 1)	throw jsl.ParamError()
			jsl.validate(utf16be, "t[al,s,Blob]", "utf16be")//!

			bs 	= this.Blob.toArray(utf16be)
			fcc	= String.fromCharCode
			l		= bs.length
			a 	= b = 0
			s		= []

			//!
			if(!this.__txt_stream && l % 2)	throw jsl.ParamError("BadSize:utf16be")//!

			while(a < l) {//!
				if(bs[a] >= 0xD800 && bs[a] <= 0xDFFF) throw jsl.ParamError("utf.UnicodeCharNotSupported:utf16be[" + a + "]")//!
				s[b++] = fcc((bs[a++] << 8) | bs[a++])
			}

			this.__txt_rb = 0

			if(this.__txt_stream) {
				this.__txt_rb = bs.length % 2
				if(this.__txt_rb) s.length--
			}
			return s.join("")
		}
		catch(e) {
			throw jsl.Error(e).clearStackTrace().trace(this, arguments)
		}
  }
	//-------------------------------------------------------------------------------
	jsl.Data.toUtf16LE = function(s) {
 		try {
			var utf16, l, a, b, c//!
			if(arguments.length !== 1)	throw jsl.ParamError()
			jsl.validate(s, "s", "s")//!

			utf16	= []
			l			= s.length
			a			= b = 0

			while(a < l) {
				c	= s.charCodeAt(a++)

				//! no Unicode points mapped inside the range [0xD800, 0xDFFF]
				if(c >= 0xD800 && c <= 0xDFFF)	throw jsl.ParamError("utf.BadChar:s:" + (a - 1))//!

				utf16[b++] = c & 0xFF
				utf16[b++] = c >> 8
			}

			return new this.Blob(utf16)
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
  }
	//-------------------------------------------------------------------------------
  jsl.Data.fromUtf16LE = function(utf16le) {
		try {
			var bs, l, a, b, s, fcc//!
			if(arguments.length !== 1)	throw jsl.ParamError()
			jsl.validate(utf16le, "t[al,s,Blob]", "utf16le")//!

			bs 	= this.Blob.toArray(utf16le)
			fcc	= String.fromCharCode
			l		= bs.length
			a 	= b = 0
			s		= []

			//!
			if(!this.__txt_stream && l % 2)	throw jsl.ParamError("BadSize:utf16le")//!

			while(a < l) {//!
				if(bs[a] >= 0xD800 && bs[a] <= 0xDFFF) throw jsl.ParamError("utf.UnicodeCharNotSupported:utf16le[" + a + "]")//!
				s[b++] = fcc(bs[a++] | (bs[a++] << 8))
			}

			this.__txt_rb = 0

			if(this.__txt_stream) {
				this.__txt_rb = bs.length % 2
				if(this.__txt_rb) s.length--
			}
			return s.join("")
		}
		catch(e) {
			throw jsl.Error(e).clearStackTrace().trace(this, arguments)
		}
  }
	/*
	  options:
	  	sbl: 		search buffer length 	(bit) [3-16]
	  	msl: 		max sequence length		(bit) [3-8]
	  	mnc:		max number of comparisons in the search buffer [1-255]

	  	note: can work in async mode -> from/tolz77(s1 + s2 + s3 + ..) = from/lz77(s1) + from/lz77(s2) + from/lz77(s3) + ..
	 */
	//-------------------------------------------------------------------------------
  jsl.Data.toLz77 = function(data, options) {
		try {
			var sbl, msl, mnc, sblv, mslv, bs, lz77, map, n, i, d, ixs, o, l, c, i0, a, ix, i2, r, i3, bi//!
			if(!arguments.length || arguments.length > 2)	throw jsl.ParamError()
			jsl.validate(data, "t[al,s,Blob]", "data")

			if(arguments.length === 2)
				jsl.validate(options, "o", "options"),
				options.sbl 	!= null && jsl.validate(options.sbl		, "i[2,16]"	, "options.sbl"),
				options.msl 	!= null && jsl.validate(options.msl		, "i[2,8]"	, "options.msl"),
				options.mnc 	!= null && jsl.validate(options.mnc		, "i[1,255]", "options.mnc")//!

			sbl		= options && options.sbl || this.__LZ_DEFAULT_SBL
			msl		= options && options.msl || this.__LZ_DEFAULT_MSL
			mnc		= options && options.mnc || this.__LZ_DEFAULT_MNC
			sblv	= (1 << sbl) - 1
			mslv	= (1 << msl) - 1
			bs 		= this.Blob.toArray(data)
			lz77	= []
			map		= {}
			n			= sbl + msl + 8
			i			= i2 = i3 = bi	= 0

			while(bs[i] != null) {

				d		= bs[i] << 24 | bs[i + 1] << 16 | bs[i + 2] << 8 | bs[i + 3]
				ixs	= map[d]

				if(ixs) {

					o		= l	= 0
					c		= bs[i]
					i0	= ixs.i = ixs.length - ixs.i > mnc ? ixs.length - mnc : ixs.i

					for(a = ixs.length - 1; a >= i0; a--) {

						ix = ixs[a]

						if(i - ix > sblv) {
							ixs.i = a + 1
							break
						}

						ix = ix + 2
						i2 = i 	+ 2
						while(i2 - i <= mslv && bs[ix] === bs[i2])
							ix++,
							i2++

						if(--i2 - i > l) {
							o	= i - ixs[a]
							l = i2 - i
							c = bs[i + l]
						}
					}

					ixs[ixs.length] = i
					i += l + 1
				}
				else {
					map[d] 		= [ i ]
					map[d].i	= 0

					o = 0
					l = 0
					c	= bs[i++]
				}

				d 				= o << msl + 8 | l << 8 | c
				r					= n - 8 + bi % 8
				lz77[i3] 	= lz77[i3++] | d >>> r

				if(r > 7)	lz77[i3++] = d >>> r - 8	& 0xFF, r -= 8
				if(r > 7)	lz77[i3++] = d >>> r - 8	& 0xFF, r -= 8
				if(r > 7)	lz77[i3++] = d >>> r - 8	& 0xFF, r -= 8

				if(r === 8)	lz77[i3++]	= (d & (1 << r) - 1) << 8 - r
				else				lz77[i3]		= (d & (1 << r) - 1) << 8 - r
				bi += n
			}

			return new this.Blob(lz77)
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	/*
	  options:
	  	sbl: 		search buffer length 	(bit) [3-16]
	  	msl: 		max sequence length		(bit) [3-8]
	 */
	//-------------------------------------------------------------------------------
  jsl.Data.fromLz77 = function(data, options) {
		try {
			var sbl, msl, bs, out, i, i2, bi, r, nb, rb, m, o, d, l, c//!
			if(!arguments.length || arguments.length > 2)	throw jsl.ParamError()
			jsl.validate(data, "t[al,s,Blob]", "data")

			if(arguments.length === 2)
				jsl.validate(options, "o", "options"),
				options.sbl != null && jsl.validate(options.sbl, "i[2,16]", "options.sbl"),
				options.msl != null && jsl.validate(options.msl, "i[2,8]"	, "options.msl")//!

			sbl		= (options && options.sbl) || this.__LZ_DEFAULT_SBL
			msl		= (options && options.msl) || this.__LZ_DEFAULT_MSL
			bs		= this.Blob.toArray(data)
			out		= []
			i			= 0
			bi 		= 0
			i2		= 0

			while(bs[i + 1] != null) {

				//1.1 offset
				//-----------------------------------------------------------------------------------------
				r 	= sbl
				nb	= bi % 8
				rb	= 8 - nb
				m 	= (1 << rb) - 1
				o		= 0

				if(r > 8)
					o = (bs[i++] & m) << nb | (bs[i] & ~m) >> rb,
					r	= r - 8

				d = bs[i] & m
				if(r < rb)	d = d >>> rb - r
				else				d = d <<  r - rb | (bs[++i] & ~m) >> 16 - r - nb

				o = o << r | d

				//1.2 length
				//-----------------------------------------------------------------------------------------
				bi = bi + sbl

				if(o) {
					nb	= bi % 8
					rb	= 8 - nb
					m 	= (1 << rb) - 1
					d 	= bs[i] & m

					if(msl < rb)	l = d >>> rb - msl
					else					l = d <<  msl - rb | (bs[++i] & ~m) >> 16 - msl - nb
					bi 	= bi + msl
				}
				else
					bi 	= bi + msl, i = ~~(bi / 8)

				//1.3 character
				//-----------------------------------------------------------------------------------------
				nb	= bi % 8
				rb	= 8 - nb
				m 	= (1 << rb) - 1
				c 	= (bs[i++] & m) << nb | (bs[i] & ~m) >> rb
				bi  = bi + 8

				//2-writing
				//-----------------------------------------------------------------------------------------
				if(o)	for(l += i2; i2 - l;) out[i2] = out[i2++ - o]
				out[i2++] = c
			}

			if(o && bs[i] == null)	out.splice(out.length - 1, 1)
			return new this.Blob(out)
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	/*
	  options:
	  	sbl: 		search buffer length 	(bit) [3-16]
	  	msl: 		max sequence length		(bit) [3-8]
	  	mnc:		max number of comparisons in the search buffer [1-255]

	  	note: can work in async mode -> from/tolzSS(s1 + s2 + s3 + ..) = from/lzSS(s1) + from/lzSS(s2) + from/lzSS(s3) + ..
	 */
	//-------------------------------------------------------------------------------
 	jsl.Data.toLzSS = function(data, options) {
		try {
			var sbl, msl, mnc, sblv, mslv, bs, lzss, map, n, i, d, ixs, o, l, c, i0, a, ix, i2, r, i3, bi//!
			if(!arguments.length || arguments.length > 2)	throw jsl.ParamError()
			jsl.validate(data, "t[al,s,Blob]", "data")

			if(arguments.length === 2)
				jsl.validate(options, "o", "options"),
				options.sbl != null && jsl.validate(options.sbl, "i[2,16]"	, "options.sbl"),
				options.msl != null && jsl.validate(options.msl, "i[2,8]"		, "options.msl"),
				options.mnc != null && jsl.validate(options.mnc, "i[1,255]"	, "options.mnc")//!

			sbl		= options && options.sbl || this.__LS_DEFAULT_SBL
			msl		= options && options.msl || this.__LS_DEFAULT_MSL
			mnc		= options && options.mnc || this.__LS_DEFAULT_MNC
			sblv	= (1 << sbl) - 1
			mslv	= (1 << msl) - 1
			bs 		= this.Blob.toArray(data)
			lzss	= []
			map		= {}
			n			= sbl + msl
			i			= i2 = i3 = bi	= 0

			while(bs[i] != null) {

				d		= bs[i] << 24 | bs[i + 1] << 16 | bs[i + 2] << 8 | bs[i + 3]
				ixs	= map[d]

				if(ixs) {

					o		= l	= 0
					i0	= ixs.i = ixs.length - ixs.i > mnc ? ixs.length - mnc : ixs.i

					for(a = ixs.length - 1; a >= i0; a--) {

						ix = ixs[a]

						if(i - ix > sblv) {
							ixs.i = a + 1
							break
						}

						ix = ix + 2
						i2 = i 	+ 2
						while(i2 - i <= mslv && bs[ix] === bs[i2])
							ix++,
							i2++

						if(--i2 - i > l) {
							o	= i - ixs[a]
							l = i2 - i
						}
					}

					ixs[ixs.length] = i
					if(o) i += l
					else	c  = bs[i++]
				}
				else {
					map[d] 		= [ i ]
					map[d].i	= 0
					o 				= 0
					c					= bs[i++]
				}

				r = bi++ % 8

				if(o) {
					if(r === 7) lzss[i3++] |= 1
					else				lzss[i3]	 |= 1 << 7 - r

					d = o << msl | l
					r	= n - 8 + bi % 8

					if(r >= 0)	lzss[i3] = lzss[i3++] | d >>> r
					else				lzss[i3] = lzss[i3] 	| d	<< -r	, r = 0

					if(r > 7)	lzss[i3++] = d >>> r - 8	& 0xFF, r -= 8
					if(r > 7)	lzss[i3++] = d >>> r - 8	& 0xFF, r -= 8

					if(r === 8)	lzss[i3++]	= (d & (1 << r) - 1) << 8 - r
					else if(r)	lzss[i3]		= (d & (1 << r) - 1) << 8 - r

					bi += n
				}
				else {
					if(r === 7) {
						i3++
						lzss[i3++] = c
					}
					else {
						lzss[i3] 	= lzss[i3++] | c >>> r + 1
						lzss[i3]	= (c & (1 << r + 1) - 1) << 7 - r
					}
					bi += 8
				}
			}

			return new this.Blob(lzss)
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	/*
	  options:
	  	sbl: 		search buffer length 	(bit) [3-16]
	  	msl: 		max sequence length		(bit) [3-8]
	 */
	//-------------------------------------------------------------------------------
  jsl.Data.fromLzSS = function(data, options) {
		try {
			var sbl, msl, bs, out, i, i2, f, bi, r, nb, rb, m, o, d, l, i3//!
			if(!arguments.length || arguments.length > 2)	throw jsl.ParamError()
			jsl.validate(data, "t[al,s,Blob]", "data")

			if(arguments.length === 2)
				jsl.validate(options, "o", "options"),
				options.sbl != null && jsl.validate(options.sbl, "i[2,16]", "options.sbl"),
				options.msl != null && jsl.validate(options.msl, "i[2,8]"	, "options.msl")//!

			sbl		= (options && options.sbl) || this.__LS_DEFAULT_SBL
			msl		= (options && options.msl) || this.__LS_DEFAULT_MSL
			bs		= this.Blob.toArray(data)
			out		= []
			i			= 0
			bi 		= 0
			i2		= 0

			while(bs[i + 1] != null) {

				f = bs[i] & 1 << 7 - bi++ % 8
				i = ~~(bi / 8)

				if(f) {

					//1 - offset
					//-----------------------------------------------------------------------------------------
					r 	= sbl
					nb	= bi % 8
					rb	= 8 - nb
					m 	= (1 << rb) - 1
					o		= 0

					if(r > 8)
						o = (bs[i++] & m) << nb | (bs[i] & ~m) >> rb,
						r	= r - 8

					d = bs[i] & m
					if(r < rb)	d = d >>> rb - r
					else				d = d <<  r - rb | (bs[++i] & ~m) >> 16 - r - nb

					o = o << r | d

					//2 - length
					//-----------------------------------------------------------------------------------------
					bi = bi + sbl

					nb	= bi % 8
					rb	= 8 - nb
					m 	= (1 << rb) - 1
					d 	= bs[i] & m

					if(msl < rb)	l = d >>> rb - msl
					else					l = d <<  msl - rb | (bs[++i] & ~m) >> 16 - msl - nb
					bi 	= bi + msl

					for(l += i2, i3 = i2 - o; i2 - l;) out[i2++] = out[i3++]
				}
				else {
					//3 - character
					//-----------------------------------------------------------------------------------------
					nb				= bi % 8
					rb				= 8 - nb
					m 				= (1 << rb) - 1
					bi  			= bi + 8
					out[i2++] = (bs[i++] & m) << nb | (bs[i] & ~m) >> rb
				}
			}

			return new this.Blob(out)
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
